#ifndef _QUEUE_H_
#define _QUEUE_H_

#include "types.h"
#include "semaphores.h"
#include "err.h"


typedef enum {
    Q_MSG_TYPE_IPC,
    Q_MSG_TYPE_DEVICE_DATA,  // e.g. network packets
    Q_MSG_TYPE_TIMER,
}queue_msg_type_t;


typedef struct _queue_msg_t
{
    /*
    * first two params shared between
    * timers and IPC messages. Order and
    * position should be kept in sync
    */
    queue_msg_type_t msg_id;
    struct _queue_msg_t *next;

    void *msg_data;
    uint16_t msg_len;

}queue_msg_t;


typedef uint32_t q_id_t;    /* used by peer for enqueue */

typedef enum
{
  COPY_DATA,
  SHARED_DATA
}enq_data_type_t;

typedef struct
{
    q_id_t q_id;
    queue_msg_type_t msg_id;
    void *msg_data;
    uint16_t msg_len;
    enq_data_type_t data_type;
    err_t err_code;
}enq_msg_t;


typedef struct
{
    q_id_t queue_id;
    const uint8_t *q_name;

    queue_msg_t head;
    queue_msg_t *tail;
    sem_t *block;  // Always locked

    err_t err_code;
}queue_t;


/*
* Data structure to use for looking
* up a queue-id by its name
*/
typedef struct
{
    q_id_t queue_id;  //out param
    const uint8_t *q_name; // in param
    err_t err_code; // out param
}queue_lookup_t;




/*
 * Parameters passed by peer to get q_id of the process
 * q_name: Name of the queue
 *
 * disconnect_handler: Handler function to call when the queue becomes invalid
 * disconnect_param: parameter to be passed to the disconnect_handler
 */
typedef struct
{
    const uint8_t *q_name;

    uint32_t disconnect_param;
    void (*disconnect_handler)(uint32_t);
}queue_subscription_t;

typedef queue_t * queue_handle_t;  /* used by self for dequeue */

/*
 * Queue operations
 */

/*
 * Dequeue:
 * Performed by owner of the queue.
 * Operates on the queue_handle known to the process
 */
err_t dequeue(queue_handle_t, queue_msg_t *);


/*
 * Enqueue:
 * Performed by peer process
 * Operates on q_id (returned by call to kernel using _find_queue)

 * The enqueue operation invokes the kernel.
 * Therefore batch mode is supported to enqueue multiple messages
 * at once
 */
err_t enqueue(q_id_t, uint8_t *data, uint16_t length);
err_t enqueue_shared_data(q_id_t, uint8_t *data, uint16_t length);
//err_t enqueue_batch(q_id_t, const queue_msg_t **);


/*
 * Q handling functions 
 */

/*
 * _create_queue:
 * Creates a queue entry in the kernel
 * The queue-entry is maintained by the kernel to let 
 * peer processes find the queue
 *
 * Returns false if queue by the same name already exists
 */
typedef struct {
    // under construction
}queue_options_t;
err_t create_queue(const uint8_t *queue_name, queue_options_t *options,
	queue_handle_t *handle);
err_t lookup_queue(const uint8_t *q_name, q_id_t *queue_id);

/*
 * _destroy_queue
 * Removes kernel entry from the queue
 */
err_t destroy_queue(queue_handle_t);

#endif
